package com.run.gogo.action;

import com.run.gogo.context.NodeContext;
import com.run.gogo.exception.NodeException;
import com.run.gogo.node.Node;
import com.run.gogo.spring.SpringBeanUtils;
import com.run.gogo.spring.transaction.IsolationEnum;
import com.run.gogo.spring.transaction.PropagationEnum;
import com.run.gogo.util.Convert;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.interceptor.NoRollbackRuleAttribute;
import org.springframework.transaction.interceptor.RollbackRuleAttribute;
import org.springframework.transaction.interceptor.RuleBasedTransactionAttribute;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import java.util.ArrayList;
import java.util.List;

public class TransactionNodeAction implements NodeAction {

    private Node innerNode;

    /* 隔离级别 */
    private String isolation;

    /* 只读 */
    private Boolean readOnly;

    /* 传播属性 */
    private String propagation;

    /* spring事务管理器 名称 */
    private String transactionManager;

    /* 回滚异常 */
    private String rollbackFor;

    /* 不回滚异常 */
    private String noRollbackFor;

    /* 事务超时时间 */
    private Integer timeout;

    private RuleBasedTransactionAttribute rba = new RuleBasedTransactionAttribute();


    public TransactionNodeAction(String isolation,Boolean readOnly,String propagation,String transactionManager
            ,String rollbackFor,String noRollbackFor,Integer timeout,Node innerNode){
        this.isolation = Convert.toStr(isolation, IsolationEnum.DEFAULT.getName());
        this.readOnly = Convert.toBool(readOnly,false);
        this.propagation = Convert.toStr(propagation, PropagationEnum.REQUIRED.getName());
        this.transactionManager = Convert.toStr(transactionManager,"transactionManager");
        this.rollbackFor = Convert.toStr(rollbackFor);
        this.noRollbackFor = Convert.toStr(noRollbackFor);
        this.timeout = Convert.toInt(timeout,50);
        this.innerNode = innerNode;

        List<RollbackRuleAttribute> rollbackRules = new ArrayList<RollbackRuleAttribute>();
        String [] rollbackFors = rollbackFor.split(",");
        for (String rbRule : rollbackFors) {
            rollbackRules.add(new RollbackRuleAttribute(rbRule));
        }
        String [] noRollbackFors = noRollbackFor.split(",");
        for (String rbRule : noRollbackFors) {
            rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
        }
        rba.setRollbackRules(rollbackRules);
    }

    @Override
    public void action(NodeContext nodeContext) {
        /* 找到事务管理器 */
        PlatformTransactionManager ptm = (PlatformTransactionManager) SpringBeanUtils.getInstance().getBean(this.transactionManager);
        /* 定义事务 */
        DefaultTransactionDefinition def = new DefaultTransactionDefinition();
        def.setPropagationBehavior(PropagationEnum.getValue(this.propagation));
        def.setIsolationLevel(IsolationEnum.getValue(this.isolation));
        def.setReadOnly(this.readOnly);
        def.setTimeout(this.timeout);
        /* 开启事务状态 */
        TransactionStatus status = ptm.getTransaction(def);
        try {
            innerNode.action(nodeContext);
            ptm.commit(status);
        }catch (Exception e){
            if(rba.rollbackOn(e)){
                ptm.rollback(status);
            }else{
                ptm.commit(status);
            }
            throw new NodeException("node handler error",e);
        }
    }
}
